// litrelate.cpp
// Customizer_Base
// Protea Customizer/Customizer Pro / Business Logic for managing literal relations
// Copyright (C) 2003, 2004, 2005 eXegeSys, Inc.
// Copyright (C) 2008 Bruce A. James
//
// This program is part of the Protea Project.
//
// The Protea Project is free software; you can redistribute it and/or modify it 
// under the terms of the GNU General Public License as published by the 
// Free Software Foundation, either version 3 of the License, or (at your 
// option) any later version.
//
// The Protea Project is distributed in the hope that it will be useful, but 
// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 
// for more details.
// 
// You should have received a copy of the GNU General Public License along 
// with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// Please send correspondence to:
//
// theproteaproject@gmail.com
//

#include "base_setup.h"

//////////////////////////////////////////////////////////////////////////////
//
// LIT_RELATE Subtransactions
//
//////////////////////////////////////////////////////////////////////////////

//@ SEC 3
//@ CHA Lit Relate Add
//@ COD LitRelateAdd
//@ TAB LIT_RELATE Write
//@ GEN Use LitRelateAdd to add a literal relation record
void LitRelateAdd( XCBuffer* buf, XCTransactionVars* vars ) 
{
	TRANS_INFUNC( LitRelateAdd );

	XCDBStatement* stmt = NULL;
	XCBuffer* lit_relate = NULL;

	XCSQLGen* query = vars->query;
	XCOrder ord;

	ord.direction = order_desc;

	//@ Determine the next value number within the group
	lit_relate = vars->myapp->CreateBuffer( FMT_LIT_RELATE );
	lit_relate->MoveCorresponding( buf, NULL );

	query->MakeSELECT( lit_relate );
	query->AddWHERE( 2, lit_relate->GetField( FLD_APPL_NBR ), lit_relate->GetField( FLD_LIT_GROUP_NBR ) );
	query->AddORDERBY( FLD_LIT_GROUP_VAL, &ord );
	stmt = vars->dbtxn->ExecuteSQL( query );
	try {
		if (stmt->Eof()) {
			buf->GetField( FLD_LIT_GROUP_VAL )->Clear();
		} else {
			short int last_number = lit_relate->GetField( FLD_LIT_GROUP_VAL )->GetShort();
			buf->GetField( FLD_LIT_GROUP_VAL )->SetShort( last_number+1 );
		};
	} catch( ... ) {
		vars->myapp->CleanupObjects( 2, &stmt, &lit_relate );
		throw;
	};
	vars->myapp->CleanupObjects( 2, &stmt, &lit_relate );

	//@ Add the literal relation record
	query->MakeFull( SQL_STMT_INSERT, buf );
	vars->dbtxn->ExecuteSQL( query, SQL_NO_RESULT );

	TRANS_OUTFUNC();
};




//@ SEC 3
//@ CHA Lit Relate Delete
//@ COD LitRelateDelete
//@ TAB LIT_RELATE Write
//@ GEN Use to delete literal relation records
void LitRelateDelete( XCBuffer* buf, XCTransactionVars* vars ) 
{
	TRANS_INFUNC( LitRelateDelete );

	XCSQLGen* query = vars->query;

	//@ *** Reorder the group numbers
	// UPDATE LIT_RELATE SET LIT_GROUP_VAL = LIT_GROUP_VAL - 1 WHERE LIT_GROUP_VAL > ???


	//@ Delete the literal relation record
	query->MakeFull( SQL_STMT_DELETE, buf );
	vars->dbtxn->ExecuteSQL( query, SQL_NO_RESULT );

	TRANS_OUTFUNC();
};




//@ SEC 3
//@ CHA Lit Relate Verify
//@ COD LitRelateVerify
//@ TAB LIT_RELATE Read
//@ GEN Use LitRelateVerify to verify a literal relation record
void LitRelateVerify( XCBuffer* buf, XCTransactionVars* vars, verify_type verify_mode, bool pro_mode ) 
{
	TRANS_INFUNC( LitRelateVerify );

	XCField* temp;
	XCBuffer* tempbuf;

	//@ Check for blank or missing literal name
	//@ ERR E (1730) LITERAL_NAME cannot be blank.
	temp = vars->buffer->GetField( FLD_LITERAL_NAME );
	if ( temp->IsBlank() )
	{
		vars->Errors->Add( ERR_IS_BLANK, SEV_ERROR, FLD_LITERAL_NAME, 1, temp );
	} else {
		//@ Get the literal number.  If the literal doesn't exist,
		//@ ERR E (5020) Literal doesn't exist.
		if ( ! LookupNumberFromName( vars, vars->buffer, buf, FLD_LITERAL_NUMBER, FLD_LITERAL_NAME, FMT_LITERAL_DEFN ) )
		{
			vars->Errors->Add( ERR_DOESNT_EXIST, SEV_ERROR, FLD_LITERAL_NAME, 1, ERR_LITERAL );
		};
	};

	//@ Check for blank or missing literal name
	//@ ERR E (1730) LIT_GROUP_NAME cannot be blank.
	temp = vars->buffer->GetField( FLD_LIT_GROUP_NAME );
	if ( temp->IsBlank() )
	{
		vars->Errors->Add( ERR_IS_BLANK, SEV_ERROR, FLD_LIT_GROUP_NAME, 1, temp );
	} else {
		//@ Get the literal group number.  If the literal group doesn't exist,
		//@ ERR E (5020) Literal Group doesn't exist.
		if ( ! LookupNumberFromName( vars, vars->buffer, buf, FLD_LIT_GROUP_NBR, FLD_LIT_GROUP_NAME, FMT_LIT_GROUP ) )
			vars->Errors->Add( ERR_DOESNT_EXIST, SEV_ERROR, FLD_LIT_GROUP_NAME, 1, ERR_LIT_GROUP );

		//@ Read the group record to determine if we are allowed to add literals to this group
		if (!pro_mode) {
			XCBuffer* group = vars->myapp->CreateBuffer( FMT_LIT_GROUP, false );
			try {
				group->MoveCorresponding( buf, vars->Errors );
				vars->query->MakeFull( SQL_STMT_SELECT, group );
				vars->dbtxn->ExecuteSQL( vars->query, SQL_NO_RESULT );

				//@ If a system object, error:
				//@ ERR C (CHANGE_CRITICAL_OBJECT)
				if (group->GetField( FLD_SYSTEM_OBJECT )->GetBool())
					vars->Errors->Add( ERR_CHANGE_CRITICAL_OBJECT, SEV_CRITICAL );
			} catch( ... ) {
				group->Release();
				throw;
			};
			group->Release();
		};
	};
	vars->Errors->Check();

	XCDBStatement* stmt;
	XCSQLGen* query = vars->query;
	tempbuf = App->CreateBuffer( FMT_LIT_RELATE );
	tempbuf->MoveCorresponding( buf, vars->Errors );
	query->MakeFull( SQL_STMT_SELECT, tempbuf );

	try {
		stmt = vars->dbtxn->ExecuteSQL( query );

		//@ If verifying an ADD transaction,
		if (verify_mode == VERIFY_ADD) 
		{
			//@ GRS

			//@ Check if literal relation already exists.  If it does,
			//@ ERR C (5026) Literal already exists in this Literal Group
			if ( !stmt->Eof() )
				vars->Errors->Add( ERR_INV_LIT_LIT_GROUP, SEV_CRITICAL, 0 );

			//@ GRE
		}
		else 
		{
			//@ GRS
			
			//@ Check if literal relation already exists.  If it doesn't,
			//@ ERR C (5025) Literal/Literal Group relationship not found 
			if ( stmt->Eof() )
				vars->Errors->Add( ERR_INV_LIT_RELATE, SEV_CRITICAL, 0 );

			//@ GRE
		};
	} catch( ... ) {
		App->CleanupObjects( 2, &stmt, &tempbuf );
		throw;
	};
	App->CleanupObjects( 2, &stmt, &tempbuf );

	TRANS_OUTFUNC();
};




//////////////////////////////////////////////////////////////////////////////
//
// Internal functions
//
//////////////////////////////////////////////////////////////////////////////

void AddLitToGroupInternal( XCTransactionVars* vars, bool pro_mode ) {
	XCBuffer* TransBuf = NULL;
	XCBuffer* lit_val = NULL;

	try {
		//@ Create LIT_RELATE buffer
		TransBuf = vars->myapp->CreateBuffer( FMT_LIT_RELATE );

		//@ Move data from the screen in the LIT_RELATE buffer
		TransBuf->MoveCorresponding( vars->buffer, vars->Errors );
		vars->Errors->Check();

		//@ SUB LitRelateVerify to verify that a literal can be added to the group
		LitRelateVerify( TransBuf, vars, VERIFY_ADD, pro_mode );

		//@ Check for errors
		vars->Errors->Check();

		//@ SUB LitRelateAdd to add the literal to the literal group
		LitRelateAdd( TransBuf, vars );

		//@ Load the literal value to return to the host
		lit_val = vars->myapp->CreateBuffer( FMT_LITERAL_VALUES );
		lit_val->MoveCorresponding( vars->buffer, vars->Errors );
		lit_val->MoveCorresponding( TransBuf, vars->Errors );
		vars->query->MakeFull( SQL_STMT_SELECT, lit_val );
		vars->dbtxn->ExecuteSQL( vars->query, SQL_NO_RESULT );

		//@ Move transaction values back to the screen buffer
		vars->buffer->MoveCorresponding( lit_val, vars->Errors );
		vars->buffer->MoveCorresponding( TransBuf, vars->Errors );
		vars->myapp->TransResponse( vars->result, vars->buffer, TRANS_HEADER_TYPE );

	} catch( ... ) {
		vars->myapp->CleanupObjects( 2, &TransBuf, &lit_val );
		throw;
	};
	vars->myapp->CleanupObjects( 2, &TransBuf, &lit_val );
};




void DelLitFromGroupInternal( XCTransactionVars* vars, bool pro_mode ) {
	XCBuffer* buf = NULL;

	//@ Create a LIT_RELATE buffer
	buf = vars->myapp->CreateBuffer( FMT_LIT_RELATE, false );

	try {
		//@ Move screen info to transaction buffer
		buf->MoveCorresponding( vars->buffer, vars->Errors );
		vars->Errors->Check();

		//@ SUB LitRelateVerify to verify that record can be deleted
		LitRelateVerify( buf, vars, VERIFY_DELETE, pro_mode );
		vars->Errors->Check();

		//@ SUB LitRelateDelete to delete the record.
		LitRelateDelete( buf, vars );
	} catch( ... ) {
		vars->myapp->CleanupObjects( 1, &buf );
		throw;
	};
	vars->myapp->CleanupObjects( 1, &buf );
};
